use actix_easy_multipart::{bytes::Bytes, text::Text, MultipartForm, MultipartFormConfig};
use actix_web::{
    get, post,
    web::{scope, Query, ServiceConfig},
};
use serde::Deserialize;

use crate::{
    error::{new_err, AppErr},
    store::firm::{self, Firm},
    web::{
        codec::{
            cbor::{new_ok_cbor, Cbor, CborRet},
            session::Session,
            user_session::UserSession,
            Void,
        },
        download::Download,
    },
};

use super::IdReq;

#[derive(Debug, MultipartForm)]
struct FirmUploadReq {
    c_type: Text<u8>,
    description: Text<String>,
    version: Text<String>,
    file: Bytes,
}

#[post("/upload")]
async fn on_upload(_u: UserSession, req: MultipartForm<FirmUploadReq>) -> Result<Void, AppErr> {
    let name: &str = req.file.file_name.as_ref().ok_or(new_err("no file name"))?;
    firm::insert(
        name,
        *req.c_type,
        &req.description,
        &req.version,
        &req.file.data,
    )
    .await?;

    Ok(Void)
}

#[derive(Debug, Deserialize)]
struct QueryReq {
    c_type: u8,
}

#[get("/query")]
async fn on_query(_: Session, req: Query<QueryReq>) -> CborRet<Box<[Firm]>> {
    let r = firm::query(req.c_type).await?;
    new_ok_cbor(r)
}

#[post("/del")]
async fn on_del(_: UserSession, req: Cbor<IdReq>) -> Result<Void, AppErr> {
    firm::del(req.id).await?;
    Ok(Void)
}

#[get("/get")]
async fn on_download(_: Session, req: Query<IdReq>) -> Result<Download, AppErr> {
    let down = firm::get(req.id).await?;
    Ok(down)
}

pub fn register(cfg: &mut ServiceConfig) {
    let limit = MultipartFormConfig::default()
        .total_limit(10 * 1024 * 1024)
        .memory_limit(10 * 1024 * 1024);

    let scope = scope("/firm")
        .app_data(limit)
        .service(on_upload)
        .service(on_query)
        .service(on_del)
        .service(on_download);
    cfg.service(scope);
}
